<?php
namespace bdhert\Tally\string;

use bdhert\Tally\Config;

/**
 * 参数处理迭代器
 * Class HandlerIterator
 * @package bdhert\Tally\string
 */
class HandlerIterator implements \Iterator {
    // member
    private array  $params;
    private array  $rules;
    private Config $config;

    // state
    private int        $length  = 0;
    private int        $index   = 0;
    private ?Decorator $handler = NULL;
    private Raw        $dataRaw;

    public function __construct(Config $config, array $params, array $rules) {
        if (array_key_exists('sign', $params)) unset($params['sign']);

        $params['secret'] = $config['secret'];
        $this->params     = $params;

        $this->index   = 0;
        $this->config  = $config;
        $this->dataRaw = new Raw();
        $this->rules   = $rules;
        $this->length  = count($rules);
    }

    /**
     * 获取当前处理器
     * @return Handler
     */
    public function current(): Handler {
        return $this->handler ?: $this->dataRaw;
    }

    /**
     * 指针状态
     * @return bool
     */
    public function valid(): bool {
        return $this->index <= $this->length && $this->index > -1;
    }

    /**
     * 获取当前规整参数
     * @return string
     */
    public function getParams(): string {
        $params  = $this->params;
        foreach($params as $key => &$param) {
            $param = is_string($param) ? $this->current()->refit($param) : $param;
        }
        ksort($params);

        return implode('.', $params);
    }

    /**
     * 指针移动
     */
    public function next() {
        if (!($next = ucfirst(strtolower($this->rules[$this->index] ?? '')))) {
            $this->index = -1;return;
        }

        $class = __NAMESPACE__ . "\\{$next}";
        $this->handler = (fn (Decorator $decorator): Decorator => $decorator)(new $class($this->current()));

        ++ $this->index;
    }

    /**
     * 获取指针key
     * @return bool|float|int|string|null
     */
    public function key() {
        return $this->index;
    }

    /**
     * 迭代器重置
     */
    public function rewind() {
        $this->index   = 0;
        $this->handler = NULL;
    }
}